#include <string.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <netdb.h>
#include <sys/un.h> 
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <fcntl.h>
#include <netinet/in.h> 
#include <arpa/inet.h>
#include <sys/mman.h>
#include <sys/stat.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <sys/time.h>
#include <sys/wait.h>
#include <sys/select.h>
#include <math.h>
#include <stdint.h>


#include "configuracion.h"
#include "constantes.h"
#include "estructuras.h"
#include "estadisticas.h"


chs glChs;
int glRPM;
char *data;
int sectores_totales_vda; 


void initialize_disk () 
{
	int fd;
	struct stat sbuf;
		
	unsigned int size;
		
	if ((fd = open("/root/fat32_chelo.disk", O_RDWR)) == -1) {
        perror("open");
        exit(1);
    }
    if (fstat(fd, &sbuf) < 0) {
        perror("fstat");
        exit(1);
    }
	size = lseek(fd, 0, SEEK_END);

    
	data = mmap(0, size, PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0); 
	madvise(data,size,2);


}


int sectoresTotales(chs datosChs) {

	int resultado;

	resultado = datosChs.cabezal * datosChs.cilindros * datosChs.sectores;

	return resultado;
}


int capacidadTotal(chs datosChs, int sizeSector) {
	return sectoresTotales(datosChs)*sizeSector;   
}

/* chs: se le pasa una direccion logica y devuelve la pista correspondiente */
int calculaChs(int sector) {
	if (sector == -1) { return -1; }
	return sector/4;
}

/* Estadisticas VDA */


double rps(int rpm)
{
	return rpm/60;
}

double segundosPorVuelta(int rpm)
{
	return 1/rps(rpm);
}

double tiempoRotacional(chs auxChs, int rpm)/* Lo devuelve en ms */
{
	return (1000* /* para pasarlo a ms */segundosPorVuelta(rpm))/auxChs.sectores;
}




int getCilindro(int pos, chs auxChs)
{
	int resultado;

	resultado = pos/auxChs.sectores +1;

	return resultado;
}

int ultimoSector( int cilindro, chs auxChs )
{
	int resultado;

	resultado = (cilindro -1)* auxChs.sectores;
	resultado = resultado + auxChs.sectores -1;

	return resultado;
}

int primerSector( int auxSector, chs auxChs )
{
	int resultado;

	resultado = auxSector + auxChs.sectores;

	return resultado;

}

char * readSector(unsigned int numsector){
	
	char *read_sec;
	int i;
	
	sleep(4);
	
	printf("En readSector \n");
	read_sec=(char *)malloc(512);
	memset(read_sec,'\0',512);
	memcpy(read_sec, data + numsector * 512, 512);

	return read_sec;
}


int writeSector(unsigned int numsector,char* data_sector){
	
	int i;
	char aux;
	char *read_sec;
	
	sleep(5);
	
    memcpy(data+(numsector * 512),data_sector, 512);
	msync(data + (numsector * 512), 512, MS_SYNC);
	
	return 1; 
}	

char * imprimirSector(unsigned int numsector){

	char* aux_read;
	int i;
	
	aux_read = readSector(numsector);
	
	/*memcpy(read,readSector(numsector),512);*/
	/*strcpy(read,readSector(numsector));	*/
	
	/*for(i=0;i<512;i++){
		printf("%x",aux_read[i]);
	}*/
	
	
	return aux_read;
	
}		

void clean(int sector1,int sector2){

   int i,aux;
   char data_sector[512];
    
   
   aux=sector1;
   
   for(i=0;i<512;i++){
      data_sector[i]="0";
   }
   
   while(aux!=sector2){
      for(i=0;i<8;i++){
         writeSector((aux-1)*512,data_sector);
      }
      aux++;
   }
  
}	

int trace(int vector[],int posicionCabezal,chs glChs,int glRPM){

	int i,f;
	int auxSectorBuscado;
	sectoresIntermedios listaSectoreYTiempos;

	i=0;
	while( i < 5  )
	{
		auxSectorBuscado = vector[i];
		if(vector[i] != -1)
		{	            
		  auxSectorBuscado = vector[i];
		  listaSectoreYTiempos = SectoresIntermedios(posicionCabezal,auxSectorBuscado,glChs,glRPM);
		  printf("SECTORES LEIDOS: ");
		  for( f = 0;f < listaSectoreYTiempos.tamanioVector;f++)
		  {
			 printf("%d |", listaSectoreYTiempos.ptrSectoresLeidos[f]);
		  }
		  printf("\n");
		   
		   

		   printf("TIEMPO CONSUMIDO: %f ms\n",listaSectoreYTiempos.tiempoDeAcceso);
		   posicionCabezal=vector[i];
 
		}
		i++;
	}  
	
	return posicionCabezal;

}

sectoresIntermedios SectoresIntermedios(int posActual, int auxSectorBuscado, chs auxChs,int rpm)
{
	sectoresIntermedios resultadoSectoresLeidos;
	int a, tamanioMem;

	int *sectoresLeidos;

	tamanioMem = 0;
	a=0;
	
	if(posActual > auxSectorBuscado)
	{
		tamanioMem = 4*2;
		sectoresLeidos = (int*) malloc(tamanioMem); /* mem para este y el que viene */
		posActual = 0;
		sectoresLeidos[a] = posActual;
		a++;
	}
	else
	{
		tamanioMem = 4;
		sectoresLeidos = (int*) malloc (tamanioMem); /* mem para el que viene */
	}


	while(getCilindro(posActual, auxChs) != getCilindro(auxSectorBuscado, auxChs))
	{
		posActual = primerSector(posActual,auxChs);
		sectoresLeidos[a] = posActual;
		a++;
		
		tamanioMem = tamanioMem + sizeof(int);
		sectoresLeidos = (int*)realloc(sectoresLeidos, tamanioMem );

	}

	if(posActual > auxSectorBuscado)
	{
	/*
		posActual = auxSectorBuscado;
		sectoresLeidos[a] = posActual;
		a++;
		
		tamanioMem = tamanioMem + sizeof(int);
		sectoresLeidos = (int*)realloc(sectoresLeidos, tamanioMem + sizeof(int) );
	*/
	
		while(posActual <= ultimoSector( getCilindro(auxSectorBuscado,auxChs), auxChs )) {
			posActual++;
			sectoresLeidos[a] = posActual;
			a++;

			tamanioMem = tamanioMem + sizeof(int);
			sectoresLeidos = (int*)realloc( sectoresLeidos, tamanioMem + sizeof(int));
		}
		posActual = posActual - auxChs.sectores;

		while(posActual <= auxSectorBuscado) {
			posActual++;
			sectoresLeidos[a] = posActual;
			a++;

			tamanioMem = tamanioMem + sizeof(int);
			sectoresLeidos = (int*)realloc(sectoresLeidos, tamanioMem + sizeof(int) );
		}
	}
	else
	{
		while(posActual != auxSectorBuscado )
		{
			posActual++;
			sectoresLeidos[a] = posActual;
			a++;
			
			tamanioMem = tamanioMem + sizeof(int);
			sectoresLeidos = (int*)realloc(sectoresLeidos, tamanioMem + sizeof(int) );
		}
	}

	resultadoSectoresLeidos.tamanioVector = a;
	resultadoSectoresLeidos.ptrSectoresLeidos = sectoresLeidos;
	resultadoSectoresLeidos.tiempoDeAcceso = a*tiempoRotacional(auxChs,rpm);
	
	
	/* despues de usar la funcion hay que liberar memoria*/
	return resultadoSectoresLeidos;
	
}


sectoresIntermedios SectoresIntermedios_Actualiza(int *posActual, int auxSectorBuscado, chs auxChs,int rpm)
{
	sectoresIntermedios resultadoSectoresLeidos;
	int a, tamanioMem;

	int *sectoresLeidos;

	tamanioMem = 0;
	a=0;
	
	if(*posActual > auxSectorBuscado)
	{
		tamanioMem = 4*2;
		sectoresLeidos = (int*) malloc(tamanioMem); /* mem para este y el que viene */
		*posActual = 0;
		sectoresLeidos[a] = *posActual;
		a++;
	}
	else
	{
		tamanioMem = 4;
		sectoresLeidos = (int*) malloc (tamanioMem); /* mem para el que viene */
	}


	while(getCilindro(*posActual, auxChs) != getCilindro(auxSectorBuscado, auxChs))
	{
		*posActual = primerSector(*posActual,auxChs);
		sectoresLeidos[a] = *posActual;
		a++;
		
		tamanioMem = tamanioMem + sizeof(int);
		sectoresLeidos = (int*)realloc(sectoresLeidos, tamanioMem );

	}

	if(*posActual > auxSectorBuscado)
	{
	/*
		*posActual = auxSectorBuscado;
		sectoresLeidos[a] = *posActual;
		a++;
		
		tamanioMem = tamanioMem + sizeof(int);
		sectoresLeidos = (int*)realloc(sectoresLeidos, tamanioMem + sizeof(int) );
	*/
	
		while(*posActual <= ultimoSector( getCilindro(auxSectorBuscado,auxChs), auxChs )) {
			*posActual = *posActual + 1;
			sectoresLeidos[a] = *posActual;
			a++;

			tamanioMem = tamanioMem + sizeof(int);
			sectoresLeidos = (int*)realloc( sectoresLeidos, tamanioMem + sizeof(int));
		}
		*posActual = *posActual - auxChs.sectores;

		while(*posActual <= auxSectorBuscado) {
			*posActual = *posActual + 1;
			sectoresLeidos[a] = *posActual;
			a++;

			tamanioMem = tamanioMem + sizeof(int);
			sectoresLeidos = (int*)realloc(sectoresLeidos, tamanioMem + sizeof(int) );
		}
		
	}
	else
	{
		while(*posActual != auxSectorBuscado )
		{
			*posActual = *posActual + 1;
			sectoresLeidos[a] = *posActual;
			a++;
			
			tamanioMem = tamanioMem + sizeof(int);
			sectoresLeidos = (int*)realloc(sectoresLeidos, tamanioMem + sizeof(int) );
		}
	}

	resultadoSectoresLeidos.tamanioVector = a;
	resultadoSectoresLeidos.ptrSectoresLeidos = sectoresLeidos;
	resultadoSectoresLeidos.tiempoDeAcceso = a*tiempoRotacional(auxChs,rpm);
	
	
	/* despues de usar la funcion hay que liberar memoria*/
	return resultadoSectoresLeidos;
	
}